#include <basic/errcode.h>
#include <basic/datetime.h>
#include <basic/para.h>
#include <basic/sockd.h>
#include <custom/svcnode.h>
#include <custom/errlog.h>

static struct
{/*{{{*/
    char program[FILE_NM_SIZE];
    char dir[LONG_FILE_NM_SIZE+1];
    unsigned int date_switch;
}/*}}}*/
_filelog={ ZEROS, ZEROS, IS_FALSE };

static int _create_file(char *program, char *dir)
{/*{{{*/
    if(dir)
    {
        if(program)
        {
            char prog_dir[LONG_FILE_NM_SIZE+1];
            extract_dirname(program, prog_dir);
            extract_basename(program, _filelog.program);
            if(dir[0] == '/')
                strcpy(_filelog.dir, dir);
            else if(BUF_IS_CLR(dir))
                strcpy(_filelog.dir, prog_dir);
            else
                sprintf(_filelog.dir, "%s/%s", prog_dir, dir);
            if(create_dir(_filelog.dir))
                return(-2);
            if(chmod(_filelog.dir, 00777) == -1)
                return(-3);
        }
        else
            return(-1);
    }
    else
    {   strcpy(_filelog.dir, "stdout");   }

    return(0);
}/*}}}*/

static void _set_date_switch()
{/*{{{*/
    _filelog.date_switch=IS_TRUE;
}/*}}}*/

static int _write_raw(char *msg)
{/*{{{*/
    if(!msg)  return(RET_ERR_PARA);

    if(BUF_IS_CLR(_filelog.dir))
        return(0);
    if(strcmp(_filelog.dir, "stdout") == 0)
    {
        fputs(msg, stdout);
        fputs(RTNS, stdout);
        return(0);
    }

    char filelog_nm[LONG_FILE_NM_SIZE+1];
    sprintf(filelog_nm, "%s/%s.log",
            _filelog.dir, _filelog.program);
    if(_filelog.date_switch) // 日期切换
    {
        char now[TIMESTAMP_SIZE+1];
        sprintf(filelog_nm+strlen(filelog_nm), ".%.8s",
                curr_timestamp_str(now));
    }
    FILE *fp;
    if((fp=fopen(filelog_nm, "a")) == NULL)
        return(-1);
    fputs(msg, fp);
    fputs(RTNS, fp);
    fclose(fp);

    return(0);
}/*}}}*/

//static int _write(char *fmt, ...)
//{/*{{{*/
//    char now[TIMESTAMP_COMMON_SIZE+1];
//    va_list arglist;
//    char log_buf[BUFFER_SIZE];
//    int offset;
//
//    va_start(arglist, fmt);
//    timestamp_fmt(curr_timestamp_str(now), NULL, now, NULL);
//    offset=sprintf(log_buf, "%s -- ", now);
//    vsnprintf(log_buf+offset, sizeof(log_buf)-offset-1, fmt, arglist);
//    va_end(arglist);
//
//    return(_write_raw(log_buf));
//}/*}}}*/

static struct
{/*{{{*/
    char program[NAME_SIZE+1];
    char snlog[LONG_FILE_NM_SIZE+1];
    SOCKET snlog_sock;
    struct sockd_addr snlog_addr;
}/*}}}*/
_errlog={ ZEROS, ZEROS, INVALID_SOCKET, { 0, 0 } };

int init_errlog(char *program, char *location)
{/*{{{*/
    if(location)
    {
        if(program)
        {
            char **array;
            int array_num;
            char loc[2][FILE_NM_SIZE+1]={ ZEROS, ZEROS };
            int i;

            if((array_num=str_split(location, ',', &array)) <= 0)
                return(-2);
            if(array_num > 2)
            {
                FREE_PTR_ARRAY(array, array_num);
                return(-3);
            }
            for(i=0; i<array_num; i++)
            {
                if(strlen(array[i]) > FILE_NM_SIZE)
                {
                    FREE_PTR_ARRAY(array, array_num);
                    return(-3);
                }
                strcpy(loc[i], array[i]);
            }
            FREE_PTR_ARRAY(array, array_num);

            // 第一个location
            trim_head_space(loc[0]);
            trim_tail_space(loc[0]);
            if(loc[0][0] == '/' && loc[0][1] == '/')
            {
                // 网络
                strcpy(_errlog.snlog, loc[0]);
                if((_errlog.snlog_sock=sockd_create()) ==
                        INVALID_SOCKET ||
                        sockd_addr_convert(loc[0], &_errlog.snlog_addr))
                {   return(-4);   }
                // 第2个location
                if(array_num == 2)
                {
                    trim_head_space(loc[1]);
                    trim_tail_space(loc[1]);
                    if(_create_file(program, loc[1]))
                    {   return(-5);   }
                    _set_date_switch();
                }
            }
            else
            {
                // 文件
                if(_create_file(program, loc[0]))
                {   return(-5);   }
                _set_date_switch();
            }
            extract_basename(program, _errlog.program);
        }
        else
        {   return(-2);   }
    }
    else
    {
        if(_create_file(program, NULL))
        {   return(-1);   }
    }
    return(0);
}/*}}}*/

int errlog(char *fmt, ...)
{/*{{{*/
    char now[TIMESTAMP_COMMON_SIZE+1];
    va_list arglist;
    char log_buf[BUFFER_SIZE];
    int prefix_size=TIMESTAMP_COMMON_SIZE+strlen(" -- ");
    int log_buf_limit=sizeof(log_buf)-prefix_size;
    char buf[prefix_size+1];
    int log_size;

    va_start(arglist, fmt);
    log_size=vsnprintf(log_buf, log_buf_limit, fmt, arglist);
    va_end(arglist);
    if(log_size >= log_buf_limit)
        log_size=log_buf_limit-1;

    if(!BUF_IS_CLR(_errlog.snlog))
    {
        char *msg_in;
        int msg_in_size=0;
        int timeout_ms=5*1000;
        unsigned int finish=IS_FALSE;

        ALLOC_MULTI_DOERR(msg_in, char, strlen(log_buf)+100,
                return(RET_ERR_ALLOC));
        CLR_BUF(msg_in);
        msg_in_size+=para_put_item(msg_in, "LOG");
        msg_in_size+=para_put_item(msg_in, _errlog.program);
        msg_in_size+=para_put_item(msg_in, log_buf);
        if(sockd_sendto(_errlog.snlog_sock, &_errlog.snlog_addr,
                    (unsigned char *)msg_in, &msg_in_size,
                    &timeout_ms) == 0)
        {   finish=IS_TRUE;   }
        free(msg_in);
        if(finish) return(0);
    }
    memmove(log_buf+prefix_size, log_buf, log_size+1);
    timestamp_fmt(curr_timestamp_str(now), NULL, now, NULL);
    sprintf(buf, "%s -- ", now);
    strncpy(log_buf, buf, prefix_size);
    return(_write_raw(log_buf));
}/*}}}*/
